package com.yanjiali.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yanjiali.constant.ArticleCoverConstant;
import com.yanjiali.entity.ArticleLike;
import com.yanjiali.enumerate.ImageTypeEnum;
import com.yanjiali.feign.SearchEngineServiceFeign;
import com.yanjiali.mappers.ArticleManageVOMapper;
import com.yanjiali.mappers.ArticleUpdateReqMapper;
import com.yanjiali.mappers.ArticleUploadReqMapper;
import com.yanjiali.mappers.GetByIdArticleRespMapper;
import com.yanjiali.model.R;
import com.yanjiali.model.req.*;
import com.yanjiali.model.resp.*;
import com.yanjiali.service.ArticleLikeService;
import com.yanjiali.vo.ArticleManageVO;
import com.yanjiali.feign.UserServiceFeign;
import com.yanjiali.model.resp.ObtainTheUsernameThroughTheIdResp;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yanjiali.mapper.ArticleMapper;
import com.yanjiali.entity.Article;
import com.yanjiali.service.ArticleService;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * @Package: com.yanjiali.service.impl
 * @Author: yanjiali
 * @Created: 2025/4/14 20:54
*/
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService{

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private UserServiceFeign userServiceFeign;

    @Autowired
    private ArticleLikeService articleLikeService;

    @Autowired
    private SearchEngineServiceFeign searchEngineServiceFeign;

    @Override
    public R<ArticleUploadResp> articleUpload(ArticleUploadReq articleUploadReq) {
        Article article = ArticleUploadReqMapper.INSTANCE.req2Entity(articleUploadReq);
        if(!whetherToSetCover(article.getCover())) {
            article.setCover(ArticleCoverConstant.coverUrl);    //给文章设置默认封面
        }
        if("".equals(article.getIntroduce()) || null == article.getIntroduce()) {
            article.setIntroduce(article.getTitle() + "，这是默认的文章简介，这是默认生成的文章简介。");   //TODO 后续使用三方库根据内容生成
        }
        article.setLikeNum(1L); //默认作者自己会给自己点赞，所以是一个
        boolean save = save(article);
        if(save) {
            return R.ok(new ArticleUploadResp("上传成功"));
        }
        return R.ok(new ArticleUploadResp("上传失败"));
    }

    @Override
    public R<ArticlePagingConditionQueryResp> articlePagingConditionQuery(ArticlePagingConditionQueryReq articlePagingConditionQueryReq) {
        //设置分页参数
        Page<Article> page = new Page();
        page.setCurrent(articlePagingConditionQueryReq.getPageCurrent());
        page.setSize(articlePagingConditionQueryReq.getPageSize());

        //构造条件构造器
        String userId = "";
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(authentication != null) {
            userId = authentication.getPrincipal().toString();
        }
        LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper
                .like(
                        !StringUtils.isEmpty(articlePagingConditionQueryReq.getQuery()),
                        Article::getTitle,
                        articlePagingConditionQueryReq.getQuery())
                .eq(!"".equals(userId), Article::getCreateBy, userId);

        //查询
        Page<Article> articlePage = page(page, lambdaQueryWrapper);

        //封装结果
        List<Article> records = articlePage.getRecords();
        if(records == null || records.size() == 0) {
            return R.ok(new ArticlePagingConditionQueryResp(new ArrayList<ArticleManageVO>(), 0L)); //没有查到数据
        }

        List<ArticleManageVO> articleManageVOS = ArticleManageVOMapper.INSTANCE.entityALL2VO(records);  //TODO 问题处
        ArticlePagingConditionQueryResp articlePagingConditionQueryResp = new ArticlePagingConditionQueryResp();
        articlePagingConditionQueryResp.setArticleManageVOList(articleManageVOS);
        articlePagingConditionQueryResp.setTotal(articlePage.getTotal());

        return R.ok(articlePagingConditionQueryResp);
    }

    @Override
    public R<ArticleUpdateResp> articleUpdate(ArticleUpdateReq articleUpdateReq) {
        Article article = ArticleUpdateReqMapper.INSTANCE.req2Entity(articleUpdateReq);
        if(!whetherToSetCover(article.getCover())) {
            article.setCover(ArticleCoverConstant.coverUrl);
        }
        //构造条件构造器
        LambdaUpdateWrapper<Article> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(article.getId() != null, Article::getId, article.getId());
        //修改
        boolean update = update(article, lambdaUpdateWrapper);
        if(update) {
            return R.ok(new ArticleUpdateResp("修改成功"));
        }
        return R.ok(new ArticleUpdateResp("修改失败"));
    }

    @Override
    public R<GetByIdArticleResp> getByIdArticle(GetByIdArticleReq getByIdArticleReq) {
        LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        String userId = null;
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(authentication != null) {
            userId = authentication.getPrincipal().toString();
        }
        lambdaQueryWrapper
                .eq(getByIdArticleReq.getId() != null, Article::getId, getByIdArticleReq.getId())
                .eq(Article::getCreateBy, userId);

        Article article = getOne(lambdaQueryWrapper);
        if(article != null) {
            GetByIdArticleResp getByIdArticleResp = GetByIdArticleRespMapper.INSTANCE.entity2Resp(article);
            return R.ok(getByIdArticleResp);
        }
        throw new IllegalArgumentException("传入的文章id参数有误");
    }

    @Override
    public R<ArticleDeleteResp> articleDelete(ArticleDeleteRep articleDeleteRep) {
        LambdaUpdateWrapper<Article> lambdaUpdateWrapper = new LambdaUpdateWrapper();
        String userId = null;
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(authentication != null) {
            userId = authentication.getPrincipal().toString();
        }
        lambdaUpdateWrapper
                .eq(articleDeleteRep.getId() != null,
                        Article::getId,
                        articleDeleteRep.getId())
                .eq(userId != null, Article::getCreateBy, userId);
        int num = articleMapper.delete(lambdaUpdateWrapper);
        if(num > 0) {
            //TODO 删除后同步的把ES数据删除
            R feignRespR = searchEngineServiceFeign.removeData(articleDeleteRep.getId() + "");
            if(feignRespR.getCode() == 200) {
                return R.ok(new ArticleDeleteResp("下架成功"));
            }
        }
        return R.fail(new ArticleDeleteResp("下架失败"));
    }

    @Override
    public R<GetByIdArticleNoNeedAuthorResp> getByIdArticleNoNeedAuthor(Long articleId) {
        LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper
                .eq(articleId != null, Article::getId, articleId);

        Article article = getOne(lambdaQueryWrapper);
        if(article == null) {
            throw new IllegalArgumentException("无效的文章id参数");
        }
        GetByIdArticleNoNeedAuthorResp getByIdArticleNoNeedAuthorResp = new GetByIdArticleNoNeedAuthorResp();

        //TODO 远程调用获取创作者用户名
        R<ObtainTheUsernameThroughTheIdResp> obtainTheUsernameThroughTheIdRespR = userServiceFeign.obtainTheUsernameThroughTheId(article.getCreateBy());
        if(obtainTheUsernameThroughTheIdRespR.getCode() != 200) {
            throw new RuntimeException("获取文章创作者失败");
        }
        String username = obtainTheUsernameThroughTheIdRespR.getData().getUsername();

        //TODO 封装对应响应参数并返回
        getByIdArticleNoNeedAuthorResp.setCover(article.getCover());
        getByIdArticleNoNeedAuthorResp.setTitle(article.getTitle());
        getByIdArticleNoNeedAuthorResp.setContent(article.getContent());
        getByIdArticleNoNeedAuthorResp.setCreateBy(username);
        getByIdArticleNoNeedAuthorResp.setCreateTime(article.getCreateTime());
        getByIdArticleNoNeedAuthorResp.setLikeNum(article.getLikeNum());
        getByIdArticleNoNeedAuthorResp.setCollectNum(article.getCollectNum());

        return R.ok(getByIdArticleNoNeedAuthorResp);
    }

    @Override
    @Transactional
    public R<LikeArticleResp> likeArticle(LikeArticleReq likeArticleReq) {
        //获取登录用户信息
        String userId = "";
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(authentication != null) {
            userId = authentication.getPrincipal().toString();
        }else {
            throw new RuntimeException("用户未登录，无法点赞");
        }

        //构造条件构造器
        LambdaQueryWrapper<ArticleLike> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ArticleLike::getUserId, userId);
        lambdaQueryWrapper.eq(likeArticleReq.getArticleId() != null, ArticleLike::getArticleId, likeArticleReq.getArticleId());

        LambdaUpdateWrapper<Article> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(Article::getId, likeArticleReq.getArticleId());

        //查询用户是否已经点赞该文章了
        ArticleLike articleLike = articleLikeService.getOne(lambdaQueryWrapper);
        if(articleLike == null) {   //点赞操作
            articleLike = new ArticleLike();
            articleLike.setArticleId(likeArticleReq.getArticleId());
            articleLike.setUserId(Long.valueOf(userId));

            boolean save = articleLikeService.save(articleLike);
            if(!save) {
                throw new RuntimeException("添加一条新的文章点赞信息失败");
            }

            lambdaUpdateWrapper.setSql("like_num = like_num + 1");
            boolean update = update(lambdaUpdateWrapper);
            if(update) {
                Article article = getById(likeArticleReq.getArticleId());
                return R.ok(new LikeArticleResp(article.getLikeNum()));
            }

        }else { //取消点赞操作
            boolean remove = articleLikeService.remove(lambdaQueryWrapper);
            if(!remove) {
                throw new RuntimeException("取消当前用户对文章的点赞记录失败");
            }

            lambdaUpdateWrapper.setSql("like_num = like_num - 1");
            boolean update = update(lambdaUpdateWrapper);
            if(update) {
                Article article = getById(likeArticleReq.getArticleId());
                return R.ok(new LikeArticleResp(article.getLikeNum()));
            }
        }

        return R.fail("点赞失败");
    }

    @Override
    public R<UpdateArticleCollectNumResp> updateArticleCollectNum(UpdateArticleCollectNumReq updateArticleCollectNumReq) {
        LambdaUpdateWrapper<Article> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper
                .eq(Article::getId, updateArticleCollectNumReq.getArticleId());

        if(updateArticleCollectNumReq.getUpdateNum() == 1) {
            lambdaUpdateWrapper.setSql("collect_num = collect_num + 1");
        }else {
            lambdaUpdateWrapper.setSql("collect_num = collect_num - 1");
        }

        boolean update = update(lambdaUpdateWrapper);
        if(update) {
            Article article = getById(updateArticleCollectNumReq.getArticleId());
            return R.ok(new UpdateArticleCollectNumResp(article.getCollectNum()));
        }

        return R.fail("修改对应文章收藏数量失败");
    }

    /**
     * 判断传入的封面是否为图片类型
     * @param cover
     * @return
     */
    private boolean whetherToSetCover(String cover) {
        if("".equals(cover) || null == cover) {
            return false;
        }

        //TODO 如果需要更严谨，那就需要判断路径是否真的可以获取到对应的图片

        int lastIndexOf = cover.lastIndexOf(".");
        String suffix = cover.substring(lastIndexOf + 1, cover.length());
        for (ImageTypeEnum imageTypeEnum : ImageTypeEnum.values()) {
            if(imageTypeEnum.getImageType().equals(suffix)) {
                return true;
            }
        }

        return false;
    }
}
